﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SilverSock;

namespace Nuzzle.Network
{
    public class LoginClient : BaseClient
    {
        public string EncryptKey { get; set; }
        public Database.Models.AccountModel Account { get; set; }

        public LoginClient(SilverSocket socket)
            : base(socket)
        {
            this.EncryptKey = Utilities.Basic.RandomString(32);

            this.Send(new Protocol.Messages.Handshake.ProtocolRequired(Definitions.DOFUS_REQUIRED, Definitions.DOFUS_CURRENT));
            this.Send(new Protocol.Messages.Connection.HelloConnectMessage(1, this.EncryptKey));
        }

        public override void OnClose()
        {
            lock (LoginServer.Clients)
            {
                Utilities.Logger.Basic("Client disconnected !");
                LoginServer.Clients.Remove(this);
            }
        }

        public override void OnPacket(Protocol.NetworkMessageReader message)
        {
            Utilities.Logger.Debug("Received packet : " + message.ID.ToString());
            try
            {
                switch (message.ID)
                {
                    case Protocol.NetworkMessageID.IdentificationMessage:
                        this.HandleIdentificationMessage(new Protocol.Messages.Connection.IdentificationMessage(message));
                        break;

                    case Protocol.NetworkMessageID.ServerSelectionMessage:
                        this.HandleServerSelectionMessage(new Protocol.Messages.Connection.ServerSelectionMessage(message));
                        break;
                }
            }
            catch (Exception e)
            {
                Utilities.Logger.Error("Can't handle packet : " + e.ToString());
            }
        }

        public override void Send(Protocol.NetworkMessage message)
        {
            Utilities.Logger.Debug("Send packet : " + message.ProtocolID.ToString());
            base.Send(message);
        }

        #region Handlers

        public void HandleIdentificationMessage(Protocol.Messages.Connection.IdentificationMessage message)
        {
            Utilities.Logger.Basic("Client try to connect with login '" + message.Login + "'");

            var account = Database.Models.AccountModel.FindFirst<Database.Models.AccountModel>("Username='" + message.Login + "'");

            if (account != null)//Check if exist
            {
                var encryptedPassword = Utilities.Basic.MD5EncodePassword(Utilities.Basic.MD5EncodePassword(account.Password) + this.EncryptKey);
                if (encryptedPassword == message.Password)//Check if correct password
                {
                    if (account.Banned == 0)//Check if banned
                    {
                        this.Account = account;
                        this.AcceptIdentificationSuccess();
                    }
                    else
                    {
                        Utilities.Logger.Error("Can't connect account '" + account.Username + "' because is banned !");
                        SendIdentificationFailedMessage(Protocol.Enums.IdentificationFailureReasonEnum.BANNED);
                        DisconnectLater(500);
                    }
                }
                else
                {
                    Utilities.Logger.Error("Wrong password for account '" + account.Username + "' !");
                    SendIdentificationFailedMessage(Protocol.Enums.IdentificationFailureReasonEnum.WRONG_CREDENTIALS);
                    DisconnectLater(500);
                }
            }
            else
            {
                Utilities.Logger.Error("Account '" + message.Login + "' not found !");
                SendIdentificationFailedMessage(Protocol.Enums.IdentificationFailureReasonEnum.WRONG_CREDENTIALS);
                DisconnectLater(500);
            }
        }

        public void HandleServerSelectionMessage(Protocol.Messages.Connection.ServerSelectionMessage message)
        {
            if (this.Account != null)
            {
                Utilities.Logger.Basic("Player '" + this.Account.Username + "' want to switch on gameserver " + message.ServerID);
                if (message.ServerID == 1)//Must be Jiva
                {
                    var ticket = new Managers.TicketManager.Ticket(Utilities.Basic.RandomString(32), this.Account);
                    Managers.TicketManager.AddTicket(ticket);

                    this.SendSelectedServerDataMessage(ticket);
                    this.DisconnectLater(500);
                }
            }
        }

        #endregion

        #region Send

        public void SendIdentificationFailedMessage(Protocol.Enums.IdentificationFailureReasonEnum reason)
        {
            this.Send(new Protocol.Messages.Connection.IdentificationFailedMessage((byte)reason));
        }

        public void SendIdentificationSuccessMessage()
        {
            this.Send(new Protocol.Messages.Connection.IdentificationSuccessMessage(this.Account.Pseudo,
                this.Account.OpLevel > 0 ? true : false, false, this.Account.ID, 0, "delete?", 1000000));
        }

        public void SendServerListMessage()
        {
            this.Send(new Protocol.Messages.Connection.ServersListMessage(
                new List<Protocol.Types.Connection.GameServerInformations>() {
                    new Protocol.Types.Connection.GameServerInformations(1, 3, 0, true,
                                    (byte)this.Account.Characters.Count, 0)
                }));
        }

        public void SendSelectedServerDataMessage(Managers.TicketManager.Ticket ticket)
        {
            this.Send(new Protocol.Messages.Connection.SelectedServerDataMessage(
                1, Utilities.Settings.AppSettings.GetStringElement("Game.Host"),
                (short)Utilities.Settings.AppSettings.GetIntElement("Game.Port"),
                true, ticket.Key));
        }

        #endregion

        #region Methods

        public void AcceptIdentificationSuccess()
        {
            if (this.Account != null)
            {
                this.SendIdentificationSuccessMessage();

                //Set characters for account selected
                this.Account.Characters = Managers.AccountManager.GetCharactersForAccount(this.Account.ID);

                this.SendServerListMessage();
            }
        }

        #endregion
    }
}
